[IA64] fix access rights in VHPT when itr.ar!=dtr.ar
authorawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Tue, 20 Mar 2007 15:32:24 +0000 (09:32 -0600)
committerawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Tue, 20 Mar 2007 15:32:24 +0000 (09:32 -0600)
This is a workaround patch for Windows 2003 Server.
Windows (vcpu>=2) set itr[1].ar=3(RWX) but dtr[1].ar=2(RW).
It causes an impossible INST_ACCESS_RIGHTS interruption via VHPT
which is used for emulating TR.

Surprisingly, windows ordinarily accepts this interruption.
But windows sometimes crashes with the message 'PANIC_STACK_SWITCH'
owing to this interruption.

Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
xen/arch/ia64/vmx/vmx_process.c
xen/arch/ia64/vmx/vtlb.c
xen/include/asm-ia64/vmmu.h

index 5e40330476b2fd65599d3636491f12de5e3c9f57..4ee7d4e8053c07b0318d02d17c86bf7e857f24af 100644 (file)
@@ -92,6 +92,11 @@ void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim,
 
     switch (vec) {
 
+    case 22:   // IA64_INST_ACCESS_RIGHTS_VECTOR
+        if (vhpt_access_rights_fixup(vcpu, ifa, 0))
+            return;
+        break;
+
     case 25:   // IA64_DISABLED_FPREG_VECTOR
 
         if (FP_PSR(vcpu) & IA64_PSR_DFH) {
index 3b6c5377b7b26e60b3b77a9119e1c6ca886b7058..9f016276029c73ddfe9097b719f51f3a48d978b1 100644 (file)
@@ -196,6 +196,37 @@ void thash_vhpt_insert(VCPU *v, u64 pte, u64 itir, u64 va, int type)
         ia64_srlz_i();
     }
 }
+
+int vhpt_access_rights_fixup(VCPU *v, u64 ifa, int is_data)
+{
+    thash_data_t *trp, *data;
+    u64 ps, tag, mask;
+
+    trp = __vtr_lookup(v, ifa, is_data);
+    if (trp) {
+        ps = _REGION_PAGE_SIZE(ia64_get_rr(ifa));
+        if (trp->ps < ps)
+            return 0;
+        ifa = PAGEALIGN(ifa, ps);
+        data = (thash_data_t *)ia64_thash(ifa);
+        tag = ia64_ttag(ifa);
+        do {
+            if (data->etag == tag) {
+                mask = trp->page_flags & PAGE_FLAGS_AR_PL_MASK;
+                if (mask != (data->page_flags & PAGE_FLAGS_AR_PL_MASK)) {
+                    data->page_flags &= ~PAGE_FLAGS_AR_PL_MASK;
+                    data->page_flags |= mask;
+                    machine_tlb_purge(ifa, ps);
+                    return 1;
+                }
+                return 0;
+            }
+            data = data->next;
+        } while(data);
+    }
+    return 0;
+}
+
 /*
  *   vhpt lookup
  */
index 905d122f68d146f8b253858e2fbf3fbeca2a9caf..84c23c2dfdcf117f25b053ae5d1dae969b7d5eba 100644 (file)
@@ -291,6 +291,7 @@ extern int thash_lock_tc(thash_cb_t *hcb, u64 va, u64 size, int rid, char cl, in
 
 #define   ITIR_RV_MASK      (((1UL<<32)-1)<<32 | 0x3)
 #define   PAGE_FLAGS_RV_MASK    (0x2 | (0x3UL<<50)|(((1UL<<11)-1)<<53))
+#define   PAGE_FLAGS_AR_PL_MASK ((0x7UL<<9)|(0x3UL<<7))
 extern u64 machine_ttag(PTA pta, u64 va);
 extern u64 machine_thash(PTA pta, u64 va);
 extern void purge_machine_tc_by_domid(domid_t domid);
@@ -309,6 +310,7 @@ extern u64 translate_phy_pte(struct vcpu *v, u64 *pte, u64 itir, u64 va);
 extern void thash_vhpt_insert(struct vcpu *v, u64 pte, u64 itir, u64 ifa,
                               int type);
 extern u64 guest_vhpt_lookup(u64 iha, u64 *pte);
+extern int vhpt_access_rights_fixup(struct vcpu *v, u64 ifa, int is_data);
 
 static inline void vmx_vcpu_set_tr (thash_data_t *trp, u64 pte, u64 itir, u64 va, u64 rid)
 {